package com.cysoft.starter.repeat.core.aspect;

import com.cysoft.starter.repeat.core.model.RepeatInfo;
import com.cysoft.starter.repeat.core.properties.RepeatSubmitProperties;
import com.cysoft.starter.repeat.core.validata.RepeatValidata;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 玖零
 * @version V0.0.1
 * @project cysoft-spring-boot-starter-repeat
 * @package com.cysoft.starter.repeat.core.aspect
 * @date 2025-03-02 15:10
 * @desc 防重复提交切面
 */
@Slf4j
@Aspect
public class RepeatAspect extends BaseAspect {

    /**
     * 防重复提交切面构造函数
     *
     * @param repeatValidata         防止重复提交验证方式
     * @param repeatSubmitProperties 防止重复提交配置文件
     */
    public RepeatAspect(RepeatValidata repeatValidata, RepeatSubmitProperties repeatSubmitProperties) {
        super(repeatValidata, repeatSubmitProperties);
    }

    /**
     * 请求方式
     */
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.PostMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.PutMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.DeleteMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.PatchMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void allAnnotationMethod() {
    }


    /**
     * 环绕通知监控重复提交
     *
     * @param point
     * @return
     */
    @Around("allAnnotationMethod()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        log.info("进入重复提交拦截切面，目标方法: {}", point.getSignature().toLongString());
        ServletRequestAttributes requestAttributes = getServletRequestAttributes();
        if (requestAttributes == null) {
            log.warn("重复提交拦截 该方法不是 web 接口请求，直接执行目标方法");
            return proceedWithExceptionHandling(point);
        }
        HttpServletRequest request = requestAttributes.getRequest();
        if (super.checkRepeat(request, point)) {
            RepeatInfo repeatInfo = super.assemblyRepeat(request, point);
            if (repeatValidata.validataRepeat(repeatInfo)) {
                log.info("重复提交，拒绝执行目标方法，请求信息: {}", repeatInfo);
                // 验证不通过返回异常提示
                throw new RuntimeException("重复提交，请稍后再试");
            }
            log.info("验证通过，执行目标方法");
        }
        return point.proceed();
    }

    /**
     * 获取ServletRequestAttributes
     *
     * @return ServletRequestAttributes对象
     */
    private ServletRequestAttributes getServletRequestAttributes() {
        return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    }

    /**
     * 封装异常处理逻辑
     *
     * @param point
     * @return
     */
    private Object proceedWithExceptionHandling(ProceedingJoinPoint point) {
        try {
            return point.proceed();
        } catch (Throwable throwable) {
            log.error("执行方法时发生异常", throwable);
            return null;
        }
    }

}
